package com.strong.utils;

import cn.hutool.core.annotation.AnnotationUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import com.strong.utils.annotation.StrongRemark;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.*;

/**
 * 代码工具类
 *
 * @author simen
 * @date 2022/11/25
 */
public class CodeUtils {

    /**
     * JAVA类型转TS类型的map
     */
    public final static Map<Class, String> MAP_TYPE_TO_TS = new HashMap<>();

    static {
        MAP_TYPE_TO_TS.put(String.class, "string");
        MAP_TYPE_TO_TS.put(Integer.class, "number");
        MAP_TYPE_TO_TS.put(Double.class, "number");
        MAP_TYPE_TO_TS.put(Float.class, "number");
        MAP_TYPE_TO_TS.put(Integer.class, "number");
        MAP_TYPE_TO_TS.put(Date.class, "Date");
        MAP_TYPE_TO_TS.put(Timer.class, "Date");
    }

    /**
     * 打印输出ts模型代码
     *
     * @param strClassName   java模型类的全名
     * @param strsProperties 包含的字段数组
     * @return {@link String}
     */
    public static void printTsModelCode(String strClassName, String[] strsProperties) {
        try {
            Class<?> clasz = Class.forName(strClassName);

            String strTsCodeFormat = """
                    export interface %s {
                    %s
                    }
                    """;

            String strJsonSchemaFormat = """
                    {
                    \t"type": "object",
                    \t"properties": {
                    %s
                    \t}
                    }
                    """;

            StringBuilder sbTsCode = new StringBuilder();
            StringBuilder sbPmCode = new StringBuilder();
            StringBuilder sbJsonSchemaCode = new StringBuilder();

            // 遍历所有字段
            for (Field field : ReflectUtil.getFields(clasz)) {
                // 如果包含的字段数组为空 或者该字段数组中存在则打印输出
                if (ArrayUtil.isEmpty(strsProperties) || ArrayUtil.contains(strsProperties, field.getName())) {
                    // 当前字段的类型
                    Class<?> typeClass = field.getType();
                    // 从JAVA类型转TS类型的map中获取对应的ts类型
                    String strTsType = CodeUtils.MAP_TYPE_TO_TS.get(typeClass);

                    // 如果当前字段类型为List类型 则取其泛型类型
                    if (typeClass.equals(List.class)) {
                        // 获取泛型的参数化类型
                        ParameterizedType type = (ParameterizedType) field.getGenericType();
                        // 获取泛型的实际参数类型数组
                        Type[] actualTypeArguments = type.getActualTypeArguments();
                        // 实际参数类型数组非空且数量为1
                        if (ArrayUtil.isNotEmpty(actualTypeArguments) && actualTypeArguments.length == 1) {
                            // 获取泛型的类型
                            Class typeArgClass = (Class) actualTypeArguments[0];
                            // 从JAVA类型转TS类型的map中获取对应的ts类型
                            strTsType = CodeUtils.MAP_TYPE_TO_TS.get(typeArgClass);
                            // 如果ts类型为空，则默认原始类名
                            if (StrUtil.isBlank(strTsType)) {
                                strTsType = typeArgClass.getSimpleName();
                            }
                            // 给泛型类型加上数组后缀
                            strTsType = strTsType + "[]";
                        }
                    }
                    StrongRemark annotation = AnnotationUtil.getAnnotation(field, StrongRemark.class);
                    sbTsCode.append(String.format("\t%s: %s \\\\%s\n", field.getName(), StrUtil.isNotBlank(strTsType) ? strTsType : typeClass.getSimpleName(), annotation.value()));
                    sbPmCode.append(String.format(" pm.expect(model.%s).to.be.ok\n", field.getName()));
                    sbJsonSchemaCode.append(String.format("\t\t\"%s\": { \"type\": \"%s\" , \"title\":\"%s\"},\n", field.getName(), MAP_TYPE_TO_TS.get(field.getGenericType()).toLowerCase(), annotation.value()));
                }
            }

            System.out.println(String.format(strTsCodeFormat, clasz.getSimpleName(), sbTsCode));
            System.out.println("======================================================");
            System.out.println(sbPmCode);
            System.out.println("======================================================");
            System.out.println(String.format(strJsonSchemaFormat, StrUtil.replaceLast(sbJsonSchemaCode, ",", "")));
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 打印输出ts模型代码
     *
     * @param strClassName str类名
     */
    public static void printTsModelCode(String strClassName) {
        printTsModelCode(strClassName, null);
    }

}
